NW | 26-SDC-Mar | TzeMing Ho | Sprint 2 | Chat App frontend and backend#78
NW | 26-SDC-Mar | TzeMing Ho | Sprint 2 | Chat App frontend and backend#78TzeMingHo wants to merge 4 commits into
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
The code could use some comments.
A useful rule of thumb is to ask yourself whether you could still explain how the code works six months from now. If the answer is uncertain, consider adding a comment to help future readers understand the intent and reasoning behind it.
Can you also include this item in the PR description?
- A description of the additional features you have implemented.
| <h1>Chat channel</h1> | ||
| </header> | ||
| <main> | ||
| <div id="chat-display-area"></div> |
There was a problem hiding this comment.
Currently the chat display area and the form can overlap when there are a lot of messages.
Can you make the necessary change or propose a method to overcome this issue?
| // backendURL: "https://tzemingho-chatapp-server-backend.hosting.codeyourfuture.io", | ||
| backendURL: "http://localhost:4000", |
There was a problem hiding this comment.
This does not look like the deployed version. 😄
| const messageInputElement = document.getElementById("message-input"); | ||
| messageInputElement.addEventListener("input", (e) => { | ||
| state.messageString = e.target.value.trim(); | ||
| }); | ||
|
|
||
| const userInputElement = document.getElementById("user-name-input"); | ||
| userInputElement.addEventListener("input", (e) => { | ||
| state.userString = e.target.value.trim(); | ||
| }); | ||
|
|
||
| document | ||
| .getElementById("message-submit-button") | ||
| .addEventListener("click", async (e) => { | ||
| await messageSubmitHandler(e, state.messageString, state.userString); | ||
| }); |
There was a problem hiding this comment.
Why immediately update messageString and userString for every "input" event instead of extracting the input values only when the user clicks the submit button?
What do you think of this arrangement?
- Assign
messageSubmitHandleras the callback to the click event - Retrieve the two pieces of input in
messageSubmitHandler
| console.error(`Message or user cannot be empty.`); | ||
| window.alert("Message or user cannot be empty."); |
There was a problem hiding this comment.
Note: Neither of these approaches is a user-friendly mechanism for showing error messages.
No change needed, but should you need to further improve the app, this is an area to consider.
| } catch (error) { | ||
| console.error(`Failed to post message: ${error}`); | ||
| } |
There was a problem hiding this comment.
Good job in anticipating potential errors (even if it is using only a placeholder error handling mechanism).
| if (response.ok) { | ||
| const confirmMessage = await response.text(); | ||
| if (confirmMessage == "sent") { | ||
| chatDisplay(); |
There was a problem hiding this comment.
Why call chatDisplay() when state.messages remains unchanged at this point?
| const port = 4000; | ||
|
|
||
| const waitingRoom = []; | ||
|
|
||
| const chatHistory = [ | ||
| { | ||
| message: "Welcome to the channel.", | ||
| user: "System", | ||
| timestamp: new Date().getTime(), | ||
| }, | ||
| ]; |
There was a problem hiding this comment.
Could consider moving these declarations before const app = express();
| if (isNaN(since)) { | ||
| return res.json(chatHistory); | ||
| } | ||
| const newMessages = chatHistory.filter(({ timestamp }) => timestamp > since); |
There was a problem hiding this comment.
An approach to reduce the amount of data sent in the response. Nicely done!
| const queryString = lastMessageTime ? `?since=${lastMessageTime}` : ""; | ||
| const url = `${state.backendURL}/messages${queryString}`; | ||
| try { | ||
| const rawResponse = await fetch(url); |
There was a problem hiding this comment.
It is not obvious that this fetch() request may remain pending for up to 25 seconds without examining the server-side implementation.
Consider adding a comment to explain this behavior.
| const callback = (message) => res.json([message]); | ||
| waitingRoom.push(callback); | ||
|
|
||
| const seconds = 25; | ||
| const milliseconds = 1000; | ||
|
|
||
| const timeout = setTimeout(() => { | ||
| const index = waitingRoom.indexOf(callback); | ||
| if (index !== -1) { | ||
| waitingRoom.splice(index, 1); | ||
| res.send([]); | ||
| } | ||
| }, seconds * milliseconds); |
There was a problem hiding this comment.
Took me quite a while to figure out how the "waiting room" logic works. I think it is over complicated.
These scenarios may be difficult to reproduce consistently, but there is a possibility that the "waiting room" logic could break under the following conditions:
- HTTP responses arrive out of order due to the asynchronous nature of request processing.
- Multiple users post messages concurrently, causing two or more messages to receive the same timestamp.
No change needed.
Learners, PR Template
Self checklist
Changelist
frontend link:
https://tzemingho-chatapp-server-frontend.hosting.codeyourfuture.io
backend link:
https://tzemingho-chatapp-server-backend.hosting.codeyourfuture.io
My prep link:
https://github.com/TzeMingHo/Project-Chat-App